| 作者:王伟 编辑:毕小烦
微服务盛行的今天,保障服务质量至关重要,作为测试人员,如何测试 Dubbo 接口呢?本文系统梳理了几种常见的测试方法,希望对大家有所启发。
一. Dubbo 简介
随着互联网行业的蓬勃发展和业务规模的持续增长,网站应用的规模也在不断扩大,同时也推动着互联网技术架构的持续演进:单一应用架构 -> 垂直应用架构 -> 分布式服务架构 -> 流动计算架构。
如下图所示:
技术架构从 All in one 的大而全逐步演化为服务独立的小而精,服务数量越来越多,服务间的调用和依赖关系也越来越复杂,用于提升服务质量的 SOA(Service-Oriented Architecture,面向服务的架构) 自然就出现了,SOA 将单一进程的应用做了拆分,形成独立对外提供服务的组件,每个组件通过网络协议对外提供服务。
服务化架构继续演进,形成了更加细粒度的微服务架构(Microservices Architecture Pattern)。在微服务架构中,一个应用会被拆分为一个个独立、可配置、可运行、可维护的子服务,极大的方便了服务的复用,不同服务的组合也能够快速响应新的业务逻辑。
同时,随着敏捷开发、持续支付、DevOps 的发展与实践,以及 Docker 和 K8S 等容器化技术和平台的成熟,微服务架构已然流行起来。
Dubbo 正是微服务开发框架中的佼佼者。
1.1 Dubbo 是什么
官网上是这样介绍的:
Dubbo 是一款微服务开发框架,它提供了 RPC 通信 与 微服务治理 两大关键能力。
这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。
同样,来自 Dubbo 官方的架构图如下所示:
先提供服务,再消费服务,Dubbo 接口测试的逻辑都在这张图上了。
接下来进入正题,看看 Dubbo 要测什么?
1.2 Dubbo 要测什么
不同应用之间通过 RPC 协议提供服务(Service 接口),而这些服务就是我们要测的内容。
下图是经典的测试金字塔:
| 图来自网络
从 ROI 来讲,自下而上效率越来越慢,成本则越来越高。从重要性来讲,服务这一层是核心,我们不仅要保障单个系统的输入输出没有问题,还要保障各系统的集成和交互没有问题。
那 RPC 是什么?
维基百科:
在分布式计算中,RPC(Remote Procedure Call,远程过程调用)是一个计算机通信协议。
该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。
RPC 是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求 - 接受回应进行信息交互的系统。
通俗的讲:
RPC 是指远程过程调用,也就是说两台服务器 A,B,一个应用部署在 A 服务器上,想要调用 B 服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。
在具备了一些基础知识之后,接下来就可以看如何测试了。
1.3 Dubbo 要怎么测
测试 Dubbo 接口大致可分为三种姿势(方式):敲命令、写代码和用工具,每种姿势都有其适用的场景。
如下图所示:
下面我们先准备好被测服务。
二. 做好准备:提供服务
既然要测试(消费)服务,首先得提供服务。
假设要测试的服务关键信息如下:
要测试的接口名为 DemoService,这里有几种典型的方法:
public interface DemoService {
// 一个简单的参数
String singleParamMethod(String name);
// 多个参数
String multiParamMethod(String name, List<String> topics);
// 参数是一个 JavaBean 对象
String beanParamMethod(Info info);
}
DemoService 中用到的 JavaBean 对象:
public class Info implements Serializable {
private String name;
private int age;
private String address;
// get、set 略
public Info() {
}
}
| 本例是在 dubbo-samples-api 的基础上修改的。
在确保 ZooKeeper 启动成功,且被测服务也启动成功之后,就可以进入测试环节了。
三. 第 1 种姿势:敲命令
3.1 Telnet
Telnet 是什么?
Telnet 协议是 Internet 远程登录服务的标准协议和主要方式,它为用户提供了在本地计算机上远程管理主机的能力。
Telnet 常用命令:
# Telnet 到主机的默认端口
$ telnet host
# Telnet 到主机的指定端口
$ telnet ip_address port
# 退出 Telnet 会话
$ quit
Dubbo 从 2.0.5 版本开始支持通过 telnet 命令来进行服务治理,但不同版本稍有区别。
对于使用 Telnet 而言, Dubbo 2.7.13 是一个分界线,之前使用 telnet IP PORT
连接到 Dubbo 协议端口(默认是 20880),之后连接到 QOS 端口(默认是 22222),命令的使用大致相同。
以 Dubbo 2.7.12 为例:
# 连接到 dubbo
$ telnet localhost 20880
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
# 查看都支持哪些命令
dubbo>help
Please input "help [command]" show detail.
cd [service] - Change default service.
clear [lines] - Clear screen.
count [service] [method] [times] - Count the service.
pwd - Print working default service.
exit - Exit the telnet.
help [command] - Show help.
invoke [service.]method(args) - Invoke the service method.
ls [-l] [service] - List services and methods.
log level - Change log level or show log
ps [-l] [port] - Print server ports and connections.
select [index] - Select the index of the method you want to invoke.
shutdown [-t <milliseconds>] - Shutdown Dubbo Application.
status [-l] - Show status.
trace [service] [method] [times] - Trace the service.
# 查看服务的接口列表
dubbo>ls
PROVIDER:
org.apache.dubbo.samples.api.DemoService
# 查看指定接口的方法列表
dubbo>ls org.apache.dubbo.samples.api.DemoService
org.apache.dubbo.samples.api.DemoService (as provider):
multiParamMethod
beanParamMethod
singleParamMethod
# 切到指定(默认)接口
dubbo>cd org.apache.dubbo.samples.api.DemoService
Used the org.apache.dubbo.samples.api.DemoService as default.
You can cancel default service by command: cd /
# 可直接调用这个接口的方法
dubbo>invoke singleParamMethod("testingweekly")
Use default service org.apache.dubbo.samples.api.DemoService.
result: "Name: testingweekly"
elapsed: 2 ms.
# 如果不切换到指定接口,也可以这样使用全路径调用接口的方法:
# invoke org.apache.dubbo.samples.api.DemoService.singleParamMethod("testingweekly")
# invoke org.apache.dubbo.samples.api.DemoService.multiParamMethod("testingweekly",["tools","articles"])
# invoke org.apache.dubbo.samples.api.DemoService.beanParamMethod({"name": "testingweekly","age": 2,"address": "https://www.yuque.com/bxiaofan/testingweekly"})
注意:
更多 Telnet 的用法:
四. 第 2 种姿势:写代码
写代码测试 Dubbo 接口得搭建一个测试项目,可以使用 https://spring.io/quickstart 快速搭建一个 Spring Boot 项目。
写代码也分两种方式:直接引用和泛化调用。
4.1 直接引用
直接引用 Dubbo 的方式需要依赖被测服务的 JAR 包,然后就可以跟写单元测试一样写 Dubbo 接口的测试用例了。
STEP 1. 在 pom.xml 中添加关键依赖:
<!-- Spring单元测试依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!-- dubbo-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.12</version>
</dependency>
<!-- ZooKeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<!-- testNG -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<!-- 你要测试的服务提供者(Provider):按实际信息修改 -->
<dependency>
<groupId>***</groupId>
<artifactId>demo-povider</artifactId>
<version>*.*.*-SNAPSHOT</version>
</dependency>
注意:
如果是本地搭建的服务,也可以将被测服务的 JAR 包直接导入测试项目。
STEP 2. 在 resources 下新建一个 XML 文件,用于配置服务提供者的信息。
假设文件名是:dubbo-consumer.xml
配置的内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 待测服务的应用名 -->
<dubbo:application name="demo-provider"/>
<!-- 注册中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" timeout="60000" check="false"/>
<!-- 要测试的接口服务 -->
<dubbo:reference id="demoService"
interface="org.apache.dubbo.samples.api.DemoService"
timeout="10000" check="false"/>
</beans>
更多配置可参考:
https://dubbo.apache.org/zh/docs/references/configuration/xml/
STEP 3. 编写测试用例
@ContextConfiguration(locations = "classpath:dubbo-consumer.xml")
public class DirectRefTest extends AbstractTestNGSpringContextTests {
@Autowired
private DemoService demoService;
@Test
public void singleParamMethodTest() {
String result = demoService.singleParamMethod("软件测试周刊");
System.out.println(result);
}
@Test
public void multiParamMethodTest() {
List<String> list = new ArrayList<String>();
list.add("测试周刊");
list.add("测试工具");
String result = demoService.multiParamMethod("软件测试周刊", list);
System.out.println(result);
}
@Test
public void multiParamMethodTest() {
List<String> list = new ArrayList<String>();
list.add("测试周刊");
list.add("测试工具");
String result = demoService.multiParamMethod("软件测试周刊", list);
System.out.println(result);
}
}
直接引用的方式来测试 Dubbo 接口,需要依赖被测服务的 JAR 包,还要配置 XML,这些都很麻烦。比较方便的是写测试用例的时候可直接查看源码来获取所需的信息。
4.2 泛化调用
Dubbo 提供了泛化调用,当我们想调用 Dubbo 服务时,无需依赖相关 JAR 包,只要知道一个接口全限定名以及入参和返参,就能调用到该服务。这就大大降低了服务提供者和消费者的耦合性。
很多 Dubbo 接口测试框架和平台就是基于此开发的。
Dubbo 官网是这样说的:
泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过 GenericService 调用所有服务实现。
更多请看:
https://dubbo.apache.org/zh/docs/advanced/generic-reference/
Dubbo 泛化调用具体应该怎么用呢?
测试用例如下:
public class GenericTest {
@Test
public void testDemoService() {
// 1.引用远程服务
ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
// 2. 设置服务提供者的应用名
reference.setApplication(new ApplicationConfig("demo-provider"));
// 3. 设置注册中心地址
reference.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
// 4. 设置要测试的接口信息
// 接口名
reference.setInterface("org.apache.dubbo.samples.api.DemoService");
// 及其他信息
// reference.setVersion("");
// reference.setGroup("");
// 5. 将其声明为泛化接口
reference.setGeneric(true);
// 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用
GenericService genericService = reference.get();
List<String> topics = new ArrayList<String>();
topics.add("测试周刊");
topics.add("测试工具");
topics.add("谁在招测试?");
// 泛化调用的方法:
// $invoke(String method, String[] parameterTypes, Object[] args)
// $invoke(String 方法名, String[] 方法的参数类型, Object[] 传给这个接口的参数)
// 例1:调用一个简单的单类型方法
Object result1 = genericService.$invoke("singleParamMethod", new String[]{"java.lang.String"}, new Object[]{"软件测试周刊"});
// 例2:调用一个多参数的方法
// Object result2 = genericService.$invoke("testMethod2", new String[]{"java.lang.String", "java.util.List"}, new Object[]{"李四", Collections.singleton("杭州")});
Object result2 = genericService.$invoke("multiParamMethod", new String[]{"java.lang.String", "java.util.List"}, new Object[]{"软件测试周刊",topics});
// 例3:调用一个参数是 Java Bean 的方法
Map<String, Object> info = new HashMap<>();
info.put("name", "软件测试周刊");
info.put("age", 2);
info.put("address", "https://www.yuque.com/bxiaofan/testingweekly");
Object result3 = genericService.$invoke("beanParamMethod", new String[]{"org.apache.dubbo.samples.api.DemoService$Info"}, new Object[]{info});
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
五. 第 3 种姿势:用工具
5.1 JMeter
JMeter 本身并不支持 Dubbo 接口的测试,需要依赖一个第三方插件:jmeter-plugins-for-apache-dubbo。
在演示如何测试之前,得先准备好环境。
STEP 1. 下载 JMeter
下载地址:
https://jmeter.apache.org/download_jmeter.cgi
我用的是最新的 Apache JMeter 5.5 版本。
STEP 2. 下载第三方插件
下载地址:
https://github.com/thubbo/jmeter-plugins-for-apache-dubbo
名称为: jmeter-plugins-dubbo-2.7.8-jar-with-dependencies.jar
。
STEP 3. 安装第三方插件
将 jmeter-plugins-dubbo-2.7.8-jar-with-dependencies.jar
放到 apache-jmeter-5.5/lib/ext/
下面。
重启 JMeter。
至此准备工作完毕。
怎么用呢?
STEP 1. 在「测试计划」上添加「线程组」
STEP 2. 在「线程组」上添加「Dubbo Sample」
如下图所示:
STEP 3. 配置 Dubbo Sample
① 测试一个简单的单类型方法:
说明:
•Registry Center:注册中心用的是 zookeeper,注册地址(Address)是:127.0.0.1:2181。超时时间(Timeout)为 6000 ms;
•RPC Protocol:dubbo:// (默认);
•Interface:点 「Get Provider List」可以获取被测服务的接口列表和方法列表,下面的 Interface 和 Method 通过选择就可以了,不必再手动输入;
•Args:
关于参数类型:
简单数据类型:填写基本类型/基本类型包装类/引用类型,如,【"int", "double", "java.lang.Integer", "java.lang.Double", "java.lang.String","java.util.List", "java.util.Map"】。
自定义数据类型:填写类的完整路径,如,【org.apache.dubbo.samples.api.Info】。
类型对照表:https://github.com/thubbo/jmeter-plugins-for-apache-dubbo/wiki/ParameterComparisonTable
复杂参数案例:https://github.com/thubbo/jmeter-plugins-for-apache-dubbo/wiki/FAQ
② 测试一个多参数的方法:
③ 测试一个参数为 Java Bean 的方法:
STEP 4. 添加「监听器」-> 查看结果树
执行后的结果如下:
5.2 Postman
我们无法直接使用 Postman 测试 Dubbo 接口,但可以自己开发一个接口服务,接收 Postman 传过来的 Dubbo 接口信息,然后通过泛化调用的方式调用相应的 Dubbo 接口,再把结果返回给 Postman 进行验证。
如下所示:
这种方式具有普适性,缺点就是会牺牲一些测试效率。
使用时是这样的:
总结
本文介绍了测试 Dubbo 接口的三种姿势:敲命令、写代码和用工具,每种姿势又有多种不同的使用方式,其中泛化调用被广泛应用于各种 Dubbo 测试工具、框架和平台之中,需重点掌握。当然,也有一些测试框架使用命令行(Telnet)的方式,不必细究。
有句话叫存在即合理,每种姿势都有其适用的场景,并没有绝对的好坏之分,我们在实际的测试过程中,也是要按需选用。
那么,你平时都在使用什么样的方式测试 Dubbo 接口呢?请留言告诉我。
参考资料
推荐阅读:
点击下方卡片关注毕小烦,我们一起
成为更好的自己
▲ 点击上方卡片关注毕小烦,一起成为更好的自己
如果文章对你有帮助,记得留言、点赞、加关注哦!